package cn.z2huo.core.lang;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;

import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>通用单例容器类
 *
 * @see cn.hutool.core.lang.Singleton
 *
 * @author z2huo
 */
public final class SingletonHolder {

    private static final ConcurrentHashMap<String, Object> POOL = new ConcurrentHashMap<>();

    private SingletonHolder(){
    }

    public static <T> T get(String key, Class<T> clazz, Object... params) {
        Assert.notNull(clazz, "Class must be not null !");
        final String completeKey = buildCompleteKey(key, clazz.getName(), params);
        return get(completeKey, () -> ReflectUtil.newInstance(clazz, params));
    }

    public static <T> T get(String key, String className, Object... params) {
        Assert.notBlank(className, "Class name must be not blank !");
        final Class<T> clazz = ClassUtil.loadClass(className);
        return get(key, clazz, params);
    }

    public static <T> T get(Class<T> clazz, Object... params) {
        return get("", clazz, params);
    }

    public static <T> T get(String className, Object... params) {
        return get("", className, params);
    }

    @SuppressWarnings("unchecked")
    public static <T> T get(String key, Func0<T> supplier) {
        return (T) POOL.computeIfAbsent(key, (k)-> supplier.callWithRuntimeException());
    }

    public static void destroy() {
        POOL.clear();
    }

    private static String buildCompleteKey(String key, String className, Object... params) {
        if (ArrayUtil.isEmpty(params)) {
            return StrUtil.format("{}#{}", key, className);
        }
        return StrUtil.format("{}#{}#{}", key, className, ArrayUtil.join(params, "_"));
    }

}
